package nz.ac.massey.groupproject.ecs2;

import java.util.ArrayList;


/*  The same type of Component can only be added once.  FIXME This is NOT checked by
    constructor and not thoroughly checked by methods.  It's up to the user to use correctly.

    .equals() method is equivalent to ==. It doesn't compare entity contents.  */
public final class ECSEntity {
	// ArrayMap
	final ArrayList<ECSComponent>    comps  =  new ArrayList<>();
	final ArrayList<ECSWorld>        worlds =  new ArrayList<>();

	public ECSEntity(ECSComponent... comps_) {
		for (var c : comps_)
			comps.add(c);
	}


	public boolean hasComponent(Class type) { return getComponent(type) != null; }
	public boolean has(Class type) { return hasComponent(type); }


	// Normally you don't need to call this.
	//
	// If you want to access some optional components, you can use System method signature
	// to match required components, then call getComponent() to retrieve optional components.
	public ECSComponent getComponent(Class type) {
		assert ECSComponent.class.isAssignableFrom(type) : "entity.getComponent(cls) called with non-Component class";

		for (var comp : comps)
			if (type.isInstance(comp))
				return comp;
		return null;
	}
	public ECSComponent get(Class type) { return getComponent(type); }



	// Add if entity doesn't have this component.  Replace if it does.
	//
	// XXX component type must match exactly. Does not work with inheritance.
	public void setComponent(ECSComponent comp) {
		for (int i = 0; i < comps.size(); i++)
			if (comp.getClass() == comps.get(i).getClass()) {
				comps.set(i, comp);
				return;
			}

		comps.add(comp);
		for (var world : worlds)
			world.notifySubscribers(ECSQuery.EventType.ADD_COMPONENT, this, comp);
	}
	public void set(ECSComponent comp) { setComponent(comp); }



	public ECSComponent removeComponent(Class type) {
		assert ECSComponent.class.isAssignableFrom(type) : "entity.removeComponent(cls) called with non-Component class";

		for (int i = 0; i < comps.size(); i++)
			if (type.isInstance(comps.get(i))) {
				var comp = comps.remove(i);
				for (var world : worlds)
					world.notifySubscribers(ECSQuery.EventType.REMOVE_COMPONENT, this, comp);
				return comp;
			}
		return null;
	}
	public boolean removeComponent(ECSComponent comp) {
		if (! comps.remove(comp)) return false;
		for (var world : worlds)
			world.notifySubscribers(ECSQuery.EventType.REMOVE_COMPONENT, this, comp);
		return true;
	}
	public ECSComponent remove(Class type)        { return removeComponent(type); }
	public boolean      remove(ECSComponent comp) { return removeComponent(comp); }
}
